// #![windows_subsystem = "windows"]

use fltk::{
    app::{self, App, Sender},
    dialog::NativeFileChooser,
    enums::CallbackTrigger,
    prelude::*,
};
use fltk_theme::WidgetTheme;

use crate::{http_server, HttpServer, UserInterface};

#[derive(Debug, Clone, Copy)]
pub enum Message {
    EnableFileListing,
    PortChanged,
    SelectServerPath,
    Start,
}

pub struct MyApp {
    app: App,
    ui: UserInterface,
    receiver: app::Receiver<Message>,
    http_server: HttpServer,
}

impl MyApp {
    pub fn new() -> Self {
        let app = App::default();
        let widget_theme = WidgetTheme::new(fltk_theme::ThemeType::Metro);
        widget_theme.apply();
        let (sender, receiver) = app::channel::<Message>();
        let mut ui = UserInterface::make_window();
        MyApp::init_ui(&mut ui, sender.clone());
        Self {
            app,
            ui,
            receiver,
            http_server: HttpServer::default(),
        }
    }

    fn init_ui(ui: &mut UserInterface, sender: Sender<Message>) {
        // ui.wind_main.set_label("baoge-tools");
        ui.input_ipaddr.add("0.0.0.0");
        ui.input_ipaddr.add("127.0.0.1");
        ui.input_ipaddr.set_value("0.0.0.0");

        ui.input_port.add("8080");
        ui.input_port.add("80");
        ui.input_port.set_value("8080");
        ui.input_port.set_trigger(CallbackTrigger::Changed);
        ui.input_port.emit(sender, Message::PortChanged);

        ui.check_button_enable_file_listing.set_value(true);
        ui.check_button_enable_file_listing
            .emit(sender, Message::EnableFileListing);

        ui.input_index.set_value("index.html");

        ui.input_server_path
            .set_value(std::env::current_dir().unwrap().to_str().unwrap());
        ui.button_browse.emit(sender, Message::SelectServerPath);

        ui.check_button_start.emit(sender, Message::Start);
    }

    pub async fn launch(&mut self) {
        tokio::spawn({
            let http_server = self.http_server.clone();
            let mut ui = self.ui.clone();
            async move {
                while let Ok(msg) = http_server.receiver.resubscribe().recv().await {
                    match msg {
                        crate::Message::Shutdown => {}
                        crate::Message::Log(log) => {
                            ui.browser_result.add(&log);
                            fltk::app::awake();
                        }
                    }
                }
            }
        });

        while self.app.wait() {
            use Message::*;
            if let Some(msg) = self.receiver.recv() {
                match msg {
                    EnableFileListing => {}
                    PortChanged => todo!(),
                    SelectServerPath => {
                        let mut nfc =
                            NativeFileChooser::new(fltk::dialog::FileDialogType::BrowseDir);
                        nfc.show();
                        // println!("{}", nfc.filename().to_string_lossy());
                        let file_name = nfc.filename().clone();
                        let server_path = file_name.to_string_lossy().clone();
                        if !server_path.is_empty() {
                            self.ui
                                .input_server_path
                                .set_value(server_path.to_string().as_str());
                        }
                    }
                    Start => {
                        let ui = self.ui.clone();
                        let is_started = ui.check_button_start.value();
                        if !is_started {
                            let sender = self.http_server.clone();
                            sender
                                .clone()
                                .sender
                                .send(http_server::Message::Shutdown)
                                .unwrap();
                        } else {
                            let ip = ui.input_ipaddr.value().unwrap();
                            let port = ui.input_port.value().unwrap();
                            let enable_file_listing = ui.check_button_enable_file_listing.value();
                            let index = ui.input_index.value();
                            let server_path = ui.input_server_path.value();
                            let server_addr = format!("{}:{}", ip, port).parse().unwrap();
                            let server_path = server_path.parse().unwrap();
                            self.http_server.http_state.set_server_addr(server_addr);
                            self.http_server.http_state.set_server_path(server_path);
                            self.http_server.http_state.set_index(index);
                            self.http_server
                                .http_state
                                .set_allow_file_listing(enable_file_listing);
                            tokio::spawn({
                                let mut http_server = self.http_server.clone();
                                async move {
                                    http_server.start_server().await.unwrap();
                                }
                            });
                        }
                    }
                }
            }
        }
    }
}
